package Day_0215.JVM;

/**
 * @author zxc
 * @date 2023/02/15 22:54
 **/
public class Heap_Divide_Generations {
    public static void main(String[] args) {
        /**
         * JVM运行时，堆内存如何进行分代
         * ===》
         * 一.Java 堆，从 GC 的角度还可以细分为: 新生代(Eden 区、 From Survivor 区和 To Survivor 区)和老年代。
         * （1）默认情况下，新生代 ( Young ) = 1/3 的堆空间大小 ; 老年代 ( Old ) = 2/3 的堆空间大小。
         * （2）默认的，Eden: from : to = 8 :1 : 1;
         * （3）JVM 每次只会使用 Eden 和其中的一块 Survivor 区域，来为对象服务，所以总是有一块Survivor区域是空闲着的。
         *
         * 二.新生代
         * ===》是用来存放新生的对象。一般占据堆的 1/3 空间。
         * 由于频繁创建对象，所以新生代会频繁触发MinorGC进行垃圾回收。
         * 新生代又分为 Eden区、 SurvivorFrom、 SurvivorTo 三个区。
         *
         * 1.Eden区
         * （1）Java 新对象的出生地（如果新创建的对象占用内存很大，则直接分配到老年代）。
         * （2）当 Eden 区内存不够的时候就会触发 MinorGC，对新生代区进行一次垃圾回收。
         *
         * 2.Survivor from 区
         * 上一次 GC 的幸存者，作为这一次 GC 的被扫描者。
         *
         * 3.Survivor to 区
         * 保留了一次 MinorGC 过程中的幸存者。
         *
         * 4.Minor GC 的过程（通俗易懂地概括来说，即 复制->清空->互换）
         * MinorGC 采用复制算法。
         * （1）eden，survivorFrom 复制到 SurvivorTo，年龄+1
         *  首先，把 Eden 和 SurvivorFrom 区域中存活的对象复制到 SurvivorTo 区域
         * （如果有对象的年龄以及达到了老年的标准，则赋值到老年代区），
         *  同时把这些对象的年龄+1
         * （如果 SurvivorTo 不够位置了就放到老年区）；
         *
         * （2） 清空 eden、 SurvivorFrom
         *  然后，清空 Eden 和 SurvivorFrom 中的对象；
         *
         * （3）SurvivorTo 和 SurvivorFrom 互换
         *  最后， SurvivorTo 和 SurvivorFrom 互换，原 SurvivorTo 成为下一次 GC 时的 SurvivorFrom区。
         *
         * 二，老年代
         * 1.主要存放应用程序中生命周期长的内存对象。
         * 老年代的对象比较稳定，所以 MajorGC （常常称之为 FULL GC）不会频繁执行。
         * 2.在进行 FULL GC前，一般都先进行了一次 Minor GC，使得有新生代对象晋身入老年代，导致空间不够用时才触发。
         * 当无法找到足够大的连续空间，分配给新创建的较大对象时，也会提前触发一次 Major GC，进行垃圾回收腾出空间。
         *
         * 3.FULL GC 采用标记-清除算法：
         * （1）首先扫描一次所有老年代，标记出存活的对象，
         * （2）然后回收没有标记的对象。
         *
         * 4.Major GC 的耗时比较长，因为要扫描再回收。
         * 5.FULL GC 会产生内存碎片，为了减少内存损耗，一般需要进行合并或者标记出来，方便下次直接分配。
         * 当老年代也满了装不下的时候，就会抛出OOM（Out of Memory）异常
         *
         * 三，永久代PermGen/元空间MetaSpace
         * 1.指内存的永久保存区域，主要存放 Class 和 Meta（元数据）的信息,
         * 2.Class 在被加载的时候被放入永久区域，它和和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。
         * 所以，这也导致了永久代的区域会随着加载的 Class 的增多而胀满，最终抛出 OOM 异常。
         *
         */

        /**
         * JVM内存为什么要堆堆内存进行分代操作？
         * ===》
         * 给堆内存分代 是为了提高对象内存分配和垃圾回收的效率。
         */

        /**
         * 为啥新生代要被划分为Eden区，SurvivorFrom区和SurvivorTo区
         * ===》
         * 1.如果没有Survivor，Eden区每进行一次Minor GC，存活的对象就会被送到老年代。
         * 老年代很快被填满，触发Major GC.老年代的内存空间远大于新生代，
         * 进行一次Full GC消耗的时间比Minor GC长得多,所以需要分为Eden和Survivor。
         * ===》
         * （1）即，若是没有Survivor区的话，则新生代每进行一次Minor GC，都会将存活的对象输送到老年代;
         * （2）导致老年代较快地被填满，从而导致大量的Full GC（Full GC所消耗的时间 远远大于 Minor GC所消耗的时间）
         *
         * 2.Survivor的存在意义，就是减少被送到老年代的对象，进而减少Full GC的发生，
         * Survivor的预筛选保证，只有经历16次Minor GC还能在新生代中存活的对象，才会被送到老年代。
         *
         * 3.设置两个Survivor区最大的好处就是解决了碎片化，刚刚新建的对象在Eden中，
         * （1）经历一次Minor GC，Eden中的存活对象就会被移动到第一块survivor space S0，Eden被清空；
         * （2）等Eden区再满了，就再触发一次Minor GC，Eden和S0中的存活对象又会被复制送入第二块survivor spaceS1
         * （复制算法，保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间，避免了碎片化的发生）
         *
         */
    }
}
